"""
Clarification item models for document analysis system.

Represents specific clarification needs identified during document analysis
with priority, type, and resolution tracking.
"""

import json
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
from typing import Dict, List, Optional, Any


class ClarificationPriority(Enum):
    """Priority levels for clarification items."""
    HIGH = "high"
    MEDIUM = "medium"
    LOW = "low"


class ClarificationType(Enum):
    """Types of clarification needed."""
    FUNCTIONAL_SCOPE = "functional_scope"
    TECHNICAL_DETAILS = "technical_details"
    USER_REQUIREMENTS = "user_requirements"
    PERFORMANCE_REQUIREMENTS = "performance_requirements"
    SECURITY_REQUIREMENTS = "security_requirements"
    INTEGRATION_REQUIREMENTS = "integration_requirements"
    TERMINOLOGY = "terminology"
    ACCEPTANCE_CRITERIA = "acceptance_criteria"


@dataclass
class ClarificationItem:
    """Represents a specific clarification need identified in document."""

    # Core attributes
    id: str
    analysis_result_id: str
    priority: ClarificationPriority
    clarification_type: ClarificationType

    # Content
    question: str
    context: str = ""
    location: str = ""
    impact_assessment: str = ""

    # Classification
    category: str = ""
    affected_requirements: List[str] = field(default_factory=list)

    # Status tracking
    status: str = "pending"  # pending, in_progress, resolved
    resolution_date: Optional[datetime] = None
    resolution_notes: str = ""

    # Additional metadata
    created_at: datetime = field(default_factory=datetime.now)
    tags: List[str] = field(default_factory=list)
    severity_score: float = 0.0

    def __post_init__(self):
        """Calculate derived attributes after initialization."""
        self._calculate_severity_score()
        self._validate_status()

    def _calculate_severity_score(self):
        """Calculate severity score based on priority and impact."""
        priority_scores = {
            ClarificationPriority.HIGH: 3.0,
            ClarificationPriority.MEDIUM: 2.0,
            ClarificationPriority.LOW: 1.0
        }

        # Base score from priority
        base_score = priority_scores.get(self.priority, 1.0)

        # Adjust based on impact assessment length (simple heuristic)
        if self.impact_assessment:
            impact_factor = min(len(self.impact_assessment) / 100, 1.5)
        else:
            impact_factor = 1.0

        # Adjust based on affected requirements count
        requirements_factor = min(len(self.affected_requirements) / 5, 1.5)

        self.severity_score = round(base_score * impact_factor * requirements_factor, 2)

    def _validate_status(self):
        """Validate status value."""
        valid_statuses = ["pending", "in_progress", "resolved", "deferred", "cancelled"]
        if self.status not in valid_statuses:
            raise ValueError(f"Invalid status: {self.status}. Must be one of {valid_statuses}")

    def resolve(self, resolution_notes: str = ""):
        """Mark clarification as resolved.

        Args:
            resolution_notes: Notes about the resolution
        """
        self.status = "resolved"
        self.resolution_date = datetime.now()
        self.resolution_notes = resolution_notes

    def defer(self, reason: str = ""):
        """Defer clarification for later resolution.

        Args:
            reason: Reason for deferring
        """
        self.status = "deferred"
        self.resolution_notes = reason

    def cancel(self, reason: str = ""):
        """Cancel clarification (no longer needed).

        Args:
            reason: Reason for cancellation
        """
        self.status = "cancelled"
        self.resolution_notes = reason

    def start_work(self):
        """Mark clarification as in progress."""
        if self.status == "pending":
            self.status = "in_progress"

    def add_affected_requirement(self, requirement_id: str):
        """Add affected requirement.

        Args:
            requirement_id: ID of affected requirement
        """
        if requirement_id not in self.affected_requirements:
            self.affected_requirements.append(requirement_id)

    def remove_affected_requirement(self, requirement_id: str):
        """Remove affected requirement.

        Args:
            requirement_id: ID of requirement to remove
        """
        if requirement_id in self.affected_requirements:
            self.affected_requirements.remove(requirement_id)

    def add_tag(self, tag: str):
        """Add tag to clarification.

        Args:
            tag: Tag to add
        """
        if tag and tag not in self.tags:
            self.tags.append(tag)

    def remove_tag(self, tag: str):
        """Remove tag from clarification.

        Args:
            tag: Tag to remove
        """
        if tag in self.tags:
            self.tags.remove(tag)

    def get_priority_value(self) -> int:
        """Get numeric priority value for sorting.

        Returns:
            Numeric priority value (higher = more important)
        """
        priority_values = {
            ClarificationPriority.HIGH: 3,
            ClarificationPriority.MEDIUM: 2,
            ClarificationPriority.LOW: 1
        }
        return priority_values.get(self.priority, 1)

    def get_type_display_name(self) -> str:
        """Get human-readable type name.

        Returns:
            Display name for clarification type
        """
        display_names = {
            ClarificationType.FUNCTIONAL_SCOPE: "Functional Scope",
            ClarificationType.TECHNICAL_DETAILS: "Technical Details",
            ClarificationType.USER_REQUIREMENTS: "User Requirements",
            ClarificationType.PERFORMANCE_REQUIREMENTS: "Performance Requirements",
            ClarificationType.SECURITY_REQUIREMENTS: "Security Requirements",
            ClarificationType.INTEGRATION_REQUIREMENTS: "Integration Requirements",
            ClarificationType.TERMINOLOGY: "Terminology",
            ClarificationType.ACCEPTANCE_CRITERIA: "Acceptance Criteria"
        }
        return display_names.get(self.clarification_type, self.clarification_type.value)

    def get_priority_display_name(self) -> str:
        """Get human-readable priority name.

        Returns:
            Display name for priority
        """
        return self.priority.value.capitalize()

    def is_resolved(self) -> bool:
        """Check if clarification is resolved.

        Returns:
            True if resolved
        """
        return self.status == "resolved"

    def is_active(self) -> bool:
        """Check if clarification needs attention.

        Returns:
            True if pending or in progress
        """
        return self.status in ["pending", "in_progress"]

    def get_age_days(self) -> int:
        """Get age of clarification in days.

        Returns:
            Age in days
        """
        delta = datetime.now() - self.created_at
        return delta.days

    def get_resolution_duration_days(self) -> Optional[int]:
        """Get duration from creation to resolution in days.

        Returns:
            Resolution duration in days, or None if not resolved
        """
        if self.resolution_date:
            delta = self.resolution_date - self.created_at
            return delta.days
        return None

    def to_dict(self) -> Dict[str, Any]:
        """Convert clarification to dictionary.

        Returns:
            Dictionary representation
        """
        return {
            "id": self.id,
            "analysis_result_id": self.analysis_result_id,
            "priority": self.priority.value,
            "clarification_type": self.clarification_type.value,
            "question": self.question,
            "context": self.context,
            "location": self.location,
            "impact_assessment": self.impact_assessment,
            "category": self.category,
            "affected_requirements": self.affected_requirements,
            "status": self.status,
            "resolution_date": self.resolution_date.isoformat() if self.resolution_date else None,
            "resolution_notes": self.resolution_notes,
            "created_at": self.created_at.isoformat(),
            "tags": self.tags,
            "severity_score": self.severity_score
        }

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> 'ClarificationItem':
        """Create clarification from dictionary.

        Args:
            data: Dictionary data

        Returns:
            ClarificationItem instance
        """
        # Convert date strings to datetime objects
        if data.get("created_at"):
            data["created_at"] = datetime.fromisoformat(data["created_at"])
        if data.get("resolution_date"):
            data["resolution_date"] = datetime.fromisoformat(data["resolution_date"])

        # Convert enum strings to enum objects
        if isinstance(data.get("priority"), str):
            data["priority"] = ClarificationPriority(data["priority"])
        if isinstance(data.get("clarification_type"), str):
            data["clarification_type"] = ClarificationType(data["clarification_type"])

        return cls(**data)

    @classmethod
    def create_high_priority(
        cls,
        id: str,
        analysis_result_id: str,
        clarification_type: ClarificationType,
        question: str,
        context: str = "",
        impact_assessment: str = ""
    ) -> 'ClarificationItem':
        """Create high priority clarification item.

        Args:
            id: Unique identifier
            analysis_result_id: Parent analysis result ID
            clarification_type: Type of clarification
            question: Clarification question
            context: Context information
            impact_assessment: Impact assessment

        Returns:
            ClarificationItem instance with high priority
        """
        return cls(
            id=id,
            analysis_result_id=analysis_result_id,
            priority=ClarificationPriority.HIGH,
            clarification_type=clarification_type,
            question=question,
            context=context,
            impact_assessment=impact_assessment
        )

    def __str__(self) -> str:
        """String representation."""
        return (f"ClarificationItem(id={self.id}, type={self.clarification_type.value}, "
                f"priority={self.priority.value}, status={self.status})")

    def __lt__(self, other) -> bool:
        """Less than comparison for sorting by priority and severity."""
        if not isinstance(other, ClarificationItem):
            return NotImplemented

        # First sort by priority (high first)
        self_priority = self.get_priority_value()
        other_priority = other.get_priority_value()

        if self_priority != other_priority:
            return self_priority > other_priority  # Reverse order (high first)

        # Then by severity score (high first)
        return self.severity_score > other.severity_score


# Utility functions for clarification management

def filter_clarifications_by_priority(
    clarifications: List[ClarificationItem],
    priority: ClarificationPriority
) -> List[ClarificationItem]:
    """Filter clarifications by priority level.

    Args:
        clarifications: List of clarification items
        priority: Priority to filter by

    Returns:
        Filtered list
    """
    return [c for c in clarifications if c.priority == priority]


def filter_clarifications_by_type(
    clarifications: List[ClarificationItem],
    clarification_type: ClarificationType
) -> List[ClarificationItem]:
    """Filter clarifications by type.

    Args:
        clarifications: List of clarification items
        clarification_type: Type to filter by

    Returns:
        Filtered list
    """
    return [c for c in clarifications if c.clarification_type == clarification_type]


def get_active_clarifications(clarifications: List[ClarificationItem]) -> List[ClarificationItem]:
    """Get active (pending or in progress) clarifications.

    Args:
        clarifications: List of clarification items

    Returns:
        List of active clarifications
    """
    return [c for c in clarifications if c.is_active()]


def sort_clarifications_by_priority(clarifications: List[ClarificationItem]) -> List[ClarificationItem]:
    """Sort clarifications by priority and severity.

    Args:
        clarifications: List of clarification items

    Returns:
        Sorted list (high priority first)
    """
    return sorted(clarifications)


def get_clarification_statistics(clarifications: List[ClarificationItem]) -> Dict[str, Any]:
    """Get statistics for clarification items.

    Args:
        clarifications: List of clarification items

    Returns:
        Statistics dictionary
    """
    total = len(clarifications)
    if total == 0:
        return {"total": 0}

    # Count by priority
    priority_counts = {}
    for priority in ClarificationPriority:
        count = len([c for c in clarifications if c.priority == priority])
        priority_counts[priority.value] = count

    # Count by type
    type_counts = {}
    for clarification_type in ClarificationType:
        count = len([c for c in clarifications if c.clarification_type == clarification_type])
        type_counts[clarification_type.value] = count

    # Count by status
    status_counts = {}
    for status in ["pending", "in_progress", "resolved", "deferred", "cancelled"]:
        count = len([c for c in clarifications if c.status == status])
        status_counts[status] = count

    # Average severity
    avg_severity = sum(c.severity_score for c in clarifications) / total

    # Age statistics
    ages = [c.get_age_days() for c in clarifications]
    avg_age = sum(ages) / len(ages) if ages else 0

    return {
        "total": total,
        "priority_distribution": priority_counts,
        "type_distribution": type_counts,
        "status_distribution": status_counts,
        "average_severity_score": round(avg_severity, 2),
        "average_age_days": round(avg_age, 1),
        "active_count": len(get_active_clarifications(clarifications)),
        "resolved_count": len([c for c in clarifications if c.is_resolved()])
    }